<template>
	<div ref="container" class="preview-3d"></div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { AStarFinder, Grid, Heuristic } from "pathfinding";

export default {
	props: {
		features: { type: Array, required: true },
		height: { type: Number, default: 8 },
		cellSize: { type: Number, default:5 },//每个网格单元的大小(米)
	},
	data() {
		return {
			scene: null,
			camera: null,
			renderer: null,
			controls: null,
			rooms: [],
			roads: [],
			startPoint: null,
			endPoint: null,
			finder: null, // A*寻路器
			gridSize: { x: 100, y: 100 }, // 网格尺寸
			grid: null, // 网格对象
			floorBounds:null,
				gridHelper: null, // 用于可视化网格的辅助对象
		};
	},
	mounted() {
		this.init3D();
		this.createBuildings();
		this.createGrid(); // 创建网格
		this.initPathfinder(); // 初始化寻路器

		this.animate();
		this.$refs.container.addEventListener("click", this.onMouseClick);
	},
	methods: {
		init3D() {
			this.scene = new THREE.Scene();
			this.scene.background = new THREE.Color(0xffffff);

			this.camera = new THREE.PerspectiveCamera(
				75,
				this.$refs.container.clientWidth /
				this.$refs.container.clientHeight,
				0.1,
				1000
			);
			this.camera.position.set(0, 100, 150);

			this.renderer = new THREE.WebGLRenderer({ antialias: true });
			this.renderer.setSize(
				this.$refs.container.clientWidth,
				this.$refs.container.clientHeight
			);
			this.$refs.container.appendChild(this.renderer.domElement);

			this.controls = new OrbitControls(
				this.camera,
				this.renderer.domElement
			);
			this.controls.mouseButtons = {
				LEFT: this.controls.mouseButtons.RIGHT,
				RIGHT: this.controls.mouseButtons.LEFT,
			};
			this.controls.screenSpacePanning = false;
			this.controls.enableDamping = true;
			this.controls.minPolarAngle = 0;
			this.controls.maxPolarAngle = Math.PI / 2;

			this.scene.add(new THREE.AmbientLight(0xffffff, 0.5));

			const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
			directionalLight.position.set(10, 10, 10);
			this.scene.add(directionalLight);
		},
		initPathfinder() {
			// 初始化A*寻路器
			this.finder = new AStarFinder({
				diagonalMovement: 2, // 允许8方向移动
				// heuristic: Heuristic.euclidean, // 改为欧几里得距离更适合3D场景
				biDirectional: true, // 暂时禁用双向搜索便于调试
				allowDiagonal: true,
				dontCrossCorners: true,
				weight: 1.5, // 增加权重帮助找到更优路径
				trackRecursion: true, //是否跟踪递归调用（调试用）
			});
		},
		createBuildings() {
			try {
				// 收集所有坐标点用于计算中心点
				let allCoordinates = [];
				this.features.forEach((feature) => {
					if (
						feature.layerType !== "path" &&
						feature.coordinates &&
						feature.coordinates[0] &&
						Array.isArray(feature.coordinates[0])
					) {
						allCoordinates = allCoordinates.concat(
							this.filterValidCoordinates(feature.coordinates[0])
						);
					}
				});

				// 计算中心点坐标
				let centerX = 112.45,
					centerY = 37.75;
				if (allCoordinates.length > 0) {
					const xs = allCoordinates
						.map((coord) => coord[0])
						.filter((x) => !isNaN(x));
					const ys = allCoordinates
						.map((coord) => coord[1])
						.filter((y) => !isNaN(y));

					if (xs.length > 0 && ys.length > 0) {
						centerX = (Math.min(...xs) + Math.max(...xs)) / 2;
						centerY = (Math.min(...ys) + Math.max(...ys)) / 2;
					}
				}

				// 清空之前的场景对象
				this.scene.traverse((child) => {
					if (
						child instanceof THREE.Mesh &&
						child !== this.controls?.object &&
						!child.isCube
					) {
						this.scene.remove(child);
					}
				});

				this.rooms = [];
				this.roads = [];
				this.floorBounds = new THREE.Box3(); // 初始化地板边界

				// 分别处理不同类型的特征
				this.features.forEach((feature) => {
					if (!feature.coordinates || !feature.coordinates[0]) {
						console.warn("特征缺少坐标数据:", feature);
						return;
					}

					if (feature.layerType === "floor") {
						const floor = this.createFloor(
							feature.coordinates[0],
							centerX,
							centerY,
							this.height
						);
						if (floor) {
							// 更新地板边界
							const floorBox = new THREE.Box3().setFromObject(floor);
							this.floorBounds.union(floorBox);
						}
					} else if (feature.layerType === "room") {
						this.createRoom(
							feature.coordinates[0],
							centerX,
							centerY,
							this.height
						);
					}
				});

				// 重新创建网格
				this.createGrid();
			} catch (error) {
				console.error("创建建筑时出错:", error);
			}
		},
		createRoom(coordinates, centerX, centerY, height) {
			// 过滤无效坐标点
			coordinates = this.filterValidCoordinates(coordinates);
			if (coordinates.length < 3) {
				console.warn("房间坐标点不足，至少需要3个点:", coordinates);
				return;
			}

			// 创建点集合
			let points = coordinates.map((coord) => {
				return new THREE.Vector2(
					(coord[0] - centerX) * 1000,
					(coord[1] - centerY) * 1000
				);
			});

			// 验证并修复自相交的形状
			if (!this.isValidShape(points)) {
				console.warn("房间形状无效，尝试修复...");
				points = this.fixShape(points);

				if (points.length < 3) {
					console.error("无法修复房间形状，跳过创建");
					return;
				}
			}

			// 创建房间形状
			const shape = new THREE.Shape(points);
			const roomHeight = height;

			// 创建几何体
			const geometry = new THREE.ExtrudeGeometry(shape, {
				depth: roomHeight,
				bevelEnabled: true,
				curveSegments: 1,
				steps: 1,
			});

			// 验证几何体
			if (!this.validateGeometry(geometry)) {
				console.error("房间几何体无效，跳过创建");
				return;
			}

			// 创建材质和网格
			const material = new THREE.MeshLambertMaterial({
				color: 0x87ceeb,
				side: THREE.DoubleSide,
				transparent: false,
				opacity: 0.5,
			});

			const room = new THREE.Mesh(geometry, material);
			room.rotation.x = -Math.PI / 2;
			room.position.y = -height + 1;
			room.userData = {
				originalColor: 0x87ceeb,
				type: "room",
				center: this.getRoomCenter(room),
				coordinates: coordinates,
			};

			this.rooms.push(room);
			this.scene.add(room);

			// 添加顶面边缘蓝色周长线
			const linePoints = points.map(
				(p) => new THREE.Vector3(p.x, p.y, roomHeight)
			);
			if (
				points.length > 0 &&
				!points[0].equals(points[points.length - 1])
			) {
				linePoints.push(
					new THREE.Vector3(points[0].x, points[0].y, roomHeight)
				);
			}

			if (linePoints.length >= 2) {
				const lineGeometry = new THREE.BufferGeometry().setFromPoints(
					linePoints
				);
				const lineMaterial = new THREE.LineBasicMaterial({
					color: 0x0000ff,
					linewidth: 5,
					transparent: false,
					depthTest: true,
					depthWrite: true,
				});

				const perimeterLine = new THREE.Line(
					lineGeometry,
					lineMaterial
				);
				perimeterLine.rotation.x = -Math.PI / 2;
				perimeterLine.position.y = -height + 1.2;
				perimeterLine.updateMatrix();
				this.scene.add(perimeterLine);
			} else {
				console.warn(
					"无法创建房间周长线，点数量不足:",
					linePoints.length
				);
			}
			// 更新网格中的障碍物
			if (this.grid) {
				this.markRoomAsObstacle(room);
			}
		},
// 创建路径规划网格
		createGrid() {
			try {
				// 清空之前的网格和路径
				if (this.grid) {
					this.grid = null;
				}

				// 移除之前的网格可视化
				if (this.gridHelper) {
					this.scene.remove(this.gridHelper);
					this.gridHelper = null;
				}

				if (this.pathMesh) {
					this.scene.remove(this.pathMesh);
					this.pathMesh = null;
				}

				this.path = null;

				if (!this.floorBounds) return;

				// 计算网格尺寸
				const size = new THREE.Vector3();
				this.floorBounds.getSize(size);

				// 确保使用相同的单元格大小
				this.gridSize = {
					x: Math.ceil(size.x / this.cellSize),
					y: Math.ceil(size.z / this.cellSize)
				};

				// 创建逻辑网格
				const gridWidth = this.gridSize.x;
				const gridHeight = this.gridSize.y;
				console.log("创建逻辑网格:", gridWidth, gridHeight, "单元格大小:", this.cellSize);
				this.grid = new Grid(gridWidth, gridHeight);

				// 初始化所有单元格为可通行
				for (let x = 0; x < gridWidth; x++) {
					for (let y = 0; y < gridHeight; y++) {
						this.grid.setWalkableAt(x, y, true);
					}
				}

				// 创建可视化网格
				const totalWidth = gridWidth * this.cellSize;
				const totalHeight = gridHeight * this.cellSize;

				// 获取地板中心点
				const center = new THREE.Vector3();
				this.floorBounds.getCenter(center);
				console.log("地板中心点:", 	totalWidth,
					gridWidth, );
				// 计算网格的起始位置
				const gridStartX = center.x - totalWidth / 2;
				const gridStartZ = center.z - totalHeight / 2;
				// 使用 THREE.GridHelper 创建可视化网格
				this.gridHelper = new THREE.GridHelper(
					totalWidth,  // 总宽度
					gridWidth,   // 网格分段数
					0xcccccc,    // 主要线条颜色
					0xeeeeee     // 次要线条颜色
				);

				// 重要：设置网格位置，使其中心与逻辑网格中心对齐
				this.gridHelper.position.set(
					center.x,
					1,  // 稍微高于地面
					center.z
				);

				// 添加到场景中
				this.scene.add(this.gridHelper);

			} catch (error) {
				console.error("创建网格时出错:", error);
			}
		},
		// 将房间区域标记为网格中的障碍物
		markRoomAsObstacle(room) {
			if (!this.grid || !room) return;

			// 获取房间的边界框
			const box = new THREE.Box3().setFromObject(room);
			const min = box.min.clone();
			const max = box.max.clone();

			// 获取网格中心点
			const gridCenterX = (this.gridSize.x * this.cellSize) / 2;
			const gridCenterZ = (this.gridSize.y * this.cellSize) / 2;

			// 将边界框坐标转换为网格坐标 (关键修正点)
			const worldToGridX = (worldX) => Math.floor((worldX + gridCenterX) / this.cellSize);
			const worldToGridZ = (worldZ) => Math.floor((worldZ + gridCenterZ) / this.cellSize);

			const minGridX = worldToGridX(min.x);
			const minGridZ = worldToGridZ(min.z);
			const maxGridX = worldToGridX(max.x);
			const maxGridZ = worldToGridZ(max.z);

			// 确保网格坐标在网格范围内
			const clampX = (x) => Math.max(0, Math.min(this.gridSize.x - 1, x));
			const clampZ = (z) => Math.max(0, Math.min(this.gridSize.y - 1, z));

			const startX = clampX(minGridX);
			const startZ = clampZ(minGridZ);
			const endX = clampX(maxGridX);
			const endZ = clampZ(maxGridZ);

			// 将房间覆盖的网格单元格标记为不可通行
			for (let x = startX; x <= endX; x++) {
				for (let z = startZ; z <= endZ; z++) {
					this.grid.setWalkableAt(x, z, false);
				}
			}
		},

		// 计算并显示路径
		calculateAndDisplayPath() {
			if (!this.startPoint || !this.endPoint) return;

			// 获取起点和终点的中心点
			const startCenter = this.getRoomCenter(this.startPoint);
			const endCenter = this.getRoomCenter(this.endPoint);

			// 获取网格中心点
			const gridCenterX = (this.gridSize.x * this.cellSize) / 2;
			const gridCenterZ = (this.gridSize.y * this.cellSize) / 2;

			// 转换为网格坐标 (关键修正点)
			const worldToGridX = (worldX) => Math.round((worldX + gridCenterX) / this.cellSize);
			const worldToGridZ = (worldZ) => Math.round((worldZ + gridCenterZ) / this.cellSize);

			const startGridX = worldToGridX(startCenter.x);
			const startGridZ = worldToGridZ(startCenter.z);
			const endGridX = worldToGridX(endCenter.x);
			const endGridZ = worldToGridZ(endCenter.z);

			// 确保坐标在网格范围内
			const clampX = (x) => Math.max(0, Math.min(this.gridSize.x - 1, x));
			const clampZ = (z) => Math.max(0, Math.min(this.gridSize.y - 1, z));

			const startX = clampX(startGridX);
			const startZ = clampZ(startGridZ);
			const endX = clampX(endGridX);
			const endZ = clampZ(endGridZ);

			// 检查起点或终点是否在障碍物中
			if (!this.grid.isWalkableAt(startX, startZ) || !this.grid.isWalkableAt(endX, endZ)) {
				console.warn("起点或终点位于障碍物中，无法计算路径");
				return;
			}

			const grid = this.grid.clone();

			this.path = this.finder.findPath(startX, startZ, endX, endZ, grid);

			// 清除之前的路径
			if (this.pathMesh) {
				this.scene.remove(this.pathMesh);
				this.pathMesh = null;
			}

			// 没有找到路径
			if (this.path.length === 0) {
				console.warn("无法找到从起点到终点的路径");
				return;
			}

			// 创建路径几何体
			const pathPoints = this.path.map(point => {
				const worldX = point[0] * this.cellSize - gridCenterX;
				const worldZ = point[1] * this.cellSize - gridCenterZ;
				return new THREE.Vector3(worldX, startCenter.y + 0.5, worldZ);
			});

			const pathGeometry = new THREE.BufferGeometry().setFromPoints(pathPoints);
			const pathMaterial = new THREE.LineBasicMaterial({
				color: 0xffd700, // 金色路径
				linewidth: 5,
				transparent: false,
				depthTest: true,
				depthWrite: true,
			});

			this.pathMesh = new THREE.Line(pathGeometry, pathMaterial);
			this.scene.add(this.pathMesh);
		},
		createFloor(coordinates, centerX, centerY, height) {
			console.log("创建楼板:", coordinates, centerX, centerY, height);
			// 过滤无效坐标点
			coordinates = this.filterValidCoordinates(coordinates);
			if (coordinates.length < 3) {
				console.warn("楼板坐标点不足，至少需要3个点:", coordinates);
				return null;
			}

			// 创建点集合
			let points = coordinates.map((coord) => {
				return new THREE.Vector2(
					(coord[0] - centerX) * 1000,
					(coord[1] - centerY) * 1000
				);
			});

			// 验证并修复自相交的形状
			if (!this.isValidShape(points)) {
				console.warn("楼板形状无效，尝试修复...");
				points = this.fixShape(points);

				if (points.length < 3) {
					console.error("无法修复楼板形状，跳过创建");
					return null;
				}
			}

			// 创建楼板形状
			const shape = new THREE.Shape(points);
			const slabThickness = 1;

			// 创建几何体
			const geometry = new THREE.ExtrudeGeometry(shape, {
				depth: slabThickness,
				bevelEnabled: true,
				curveSegments: 1,
				steps: 1,
			});

			// 验证几何体
			if (!this.validateGeometry(geometry)) {
				console.error("楼板几何体无效，跳过创建");
				return null;
			}

			// 创建材质和网格
			const material = new THREE.MeshLambertMaterial({
				color: 0xf5f5f5,
				side: THREE.DoubleSide,
				transparent: false,
				opacity: 1.0,
			});

			const floorSlab = new THREE.Mesh(geometry, material);
			floorSlab.rotation.x = -Math.PI / 2;
			floorSlab.position.y = -height + slabThickness / 2;
			this.scene.add(floorSlab);
			return floorSlab;
		},
		getRoomCenter(room) {
			if (!room) return new THREE.Vector3();

			const box = new THREE.Box3().setFromObject(room);
			const center = new THREE.Vector3();
			box.getCenter(center);
			return center;
		},

		// 过滤无效坐标点
		filterValidCoordinates(coordinates) {
			if (!Array.isArray(coordinates)) {
				console.warn("坐标数据不是数组:", coordinates);
				return [];
			}

			return coordinates.filter((coord) => {
				if (!Array.isArray(coord) || coord.length < 2) {
					console.warn("无效坐标点:", coord);
					return false;
				}

				// 检查坐标是否为有效数字
				if (isNaN(coord[0]) || isNaN(coord[1])) {
					console.warn("坐标包含NaN值:", coord);
					return false;
				}

				// 检查坐标是否为无穷大
				if (!isFinite(coord[0]) || !isFinite(coord[1])) {
					console.warn("坐标包含无穷大值:", coord);
					return false;
				}

				return true;
			});
		},
		// 验证形状有效性
		isValidShape(points) {
			return true;
			if (!Array.isArray(points) || points.length < 3) {
				return false;
			}

			// 检查是否有重复点
			for (let i = 0; i < points.length; i++) {
				for (let j = i + 1; j < points.length; j++) {
					if (points[i].equals(points[j])) {
						return false;
					}
				}
			}

			return true;
		},
		// 修复无效形状
		fixShape(points) {
			if (!Array.isArray(points)) return [];

			// 移除重复点
			const uniquePoints = [];
			points.forEach((point) => {
				if (!uniquePoints.some((p) => p.equals(point))) {
					uniquePoints.push(point);
				}
			});

			return uniquePoints;
		},
		// 验证几何体有效性
		validateGeometry(geometry) {
			if (
				!geometry ||
				!geometry.attributes ||
				!geometry.attributes.position
			) {
				return false;
			}

			const position = geometry.attributes.position;

			// 检查顶点数量
			if (position.count < 3) {
				console.warn("几何体顶点数量不足:", position.count);
				return false;
			}

			// 检查是否有NaN或无穷大值
			for (let i = 0; i < position.count; i++) {
				if (
					isNaN(position.getX(i)) ||
					isNaN(position.getY(i)) ||
					isNaN(position.getZ(i)) ||
					!isFinite(position.getX(i)) ||
					!isFinite(position.getY(i)) ||
					!isFinite(position.getZ(i))
				) {
					console.warn("几何体包含无效顶点数据，索引:", i);
					return false;
				}
			}

			return true;
		},

		onMouseClick(event) {
			if (!this.$refs.container) return;

			// 计算鼠标在标准化设备坐标中的位置 (-1 到 1)
			const rect = this.$refs.container.getBoundingClientRect();
			const mouse = new THREE.Vector2();
			mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
			mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

			// 创建射线投射器
			if (!this.camera) return;

			const raycaster = new THREE.Raycaster();
			raycaster.setFromCamera(mouse, this.camera);

			// 检测与房间对象的交集
			if (!this.rooms || this.rooms.length === 0) return;

			const intersects = raycaster.intersectObjects(this.rooms);

			if (intersects.length > 0 && intersects[0].object) {
				const clickedRoom = intersects[0].object;

				// 重置所有房间颜色
				this.rooms.forEach((room) => {
					if (room && room.material && room.userData) {
						room.material.color.set(room.userData.originalColor);
					}
				});

				// 点击逻辑：如果没有起点，设置为起点；如果已有起点但没有终点，设置为终点；如果都有，重置并设置新起点
				if (!this.startPoint) {
					// 设置起点
					this.startPoint = clickedRoom;
					if (this.startPoint && this.startPoint.material) {
						this.startPoint.material.color.set(0x00ff00);
					}
					this.endPoint = null; // 重置终点
				} else if (!this.endPoint && clickedRoom !== this.startPoint) {
					// 设置终点（不能与起点相同）
					this.endPoint = clickedRoom;
					if (this.endPoint && this.endPoint.material) {
						this.endPoint.material.color.set(0xff0000);
					}

					// 当起点和终点都存在时计算并绘制路径
					if (this.startPoint && this.endPoint) {
						this.calculateAndDisplayPath();
					}
				} else {
					// 重置并设置新起点
					this.startPoint = clickedRoom;
					if (this.startPoint && this.startPoint.material) {
						this.startPoint.material.color.set(0x00ff00);
					}
					this.endPoint = null; // 重置终点
					// 清除路径
					if (this.pathMesh) {
						this.scene.remove(this.pathMesh);
						this.pathMesh = null;
					}
					this.path = null;
				}
			}
		},
		animate() {
			requestAnimationFrame(this.animate.bind(this));
			if (this.controls) this.controls.update();
			if (this.renderer && this.scene && this.camera) {
				this.renderer.render(this.scene, this.camera);
			}
		},
	},
	beforeUnmount() {
		// 清理资源
		if (this.$refs.container) {
			this.$refs.container.removeEventListener(
				"click",
				this.onMouseClick
			);
		}

		if (this.renderer) {
			this.renderer.dispose();
			if (this.$refs.container) {
				this.$refs.container.removeChild(this.renderer.domElement);
			}
		}

		if (this.controls) this.controls.dispose();
	},
	watch: {
		features: {
			deep: true,
			handler() {
				// 特征变化时重新渲染
				if (!this.scene) return;

				this.scene.traverse((child) => {
					if (
						child instanceof THREE.Mesh &&
						child !== this.controls?.object &&
						!child.isCube
					) {
						this.scene.remove(child);
					}
				});

				this.rooms = [];
				this.roads = [];

				this.createBuildings();
			},
		},
	},
};
</script>

<style scoped>
.preview-3d {
	width: 100%;
	height: 100%;
}
</style>
